using System.Collections.Generic;
using System.Linq;
using SmartBot.Plugins.API;
using SmartBotAPI.Battlegrounds;
using SmartBotAPI.Battlegrounds.Actions;

//Friendly names can be found in the Cards.Battleground class

/*

BATTLEGROUND PROFILE

The instance of your profile is kept alive during the whole bot's lifetime, there are two methods you can use to reset your variables between games :
-OnNewGameSignalReceived() is triggered after mulligen phase of each game
-OnNewTurnSignalReceived() is triggered after each new local turn phase (after the fighting phase)

The profile will determine bot's behavior using two methods :
-HandleBoard() method is used to determine the next action that need to be executed for the current board/situation
-HandleDiscoverChoices() method is used to choose the card from the spells you earn when upgrading a minion

Action list that can be return in HandleBoard() method :

-BuyMinion(SBBGCard card)
-SellMinion(SBBGCard card)
-PlayMinion(SBBGCard card, int index)
-PlayMinionOnTarget(SBBGCard card, SBBGCard targetCard, int index)
-PlayHeroPower()
-PlayHeroPowerOnTarget(SBBGCard target)
-PlayDiscoverSpell(SBBGCard card)
-ChangeMinionIndex(SBBGCard minion, int newIndex)
-FreezeChoices()
-RerollChoices()
-TavernUp()
-DoNothing()

The turn will stop after you return a DoNothing() action
Below are some basic samples on how to use basic actions

One important point is that you need to use PlayMinionOnTarget and PlayHeroPowerOnTarget when  needed. Some minions require a target in some situations, it's up to you to use the correct action with a correct target, the bot will not fix errors and doesn't have any targetting system implemented, wrong use will result in the bot being stuck.

I'll anwser any questions related to the Battleground profiles on the forum after the expansion is released.

*/

public class TestBGProfile : BGProfile
{

    public SBBGAction HandleBoard(SBBGBoard board)
    {
        if(board.DoChoicesContainUpgradableCard() && board.CanBuyMinion())
        {
            var upgradableCard = board.GetUpgradableCardIfAny();
            return new BuyMinion(board.Choices.First(x => x.CardId == upgradableCard.CardId));
        }

        if (board.HasDiscoverToPlay())
        {
            return new PlayDiscoverSpell(board.Hand.First(x => x.IsDiscover));
        }

        if (board.CanUpgradeTavern() && board.TavernLevelUpCost <= 4)
        {
            return new TavernUp();
        }

        if (board.CanBuyMinion())
        {
            return new BuyMinion(board.Choices[0]);
        }

        if(board.CanPlayMinion())
        {
            return new PlayMinion(board.Hand[0], 0);
        }

        foreach(var minion in board.Minions.ToArray())
        {
            if(minion.Taunt && minion.Index < board.GetLastIndex() && !board.AreAllMinionsOnTheRightTaunts(minion))
            {
                return new ChangeMinionIndex(minion, board.GetLastIndex());
            }
        }

       // return new PlayHeroPower();
       // return new PlayHeroPowerOnTarget(SBBGCard target);
       // return new PlayMinionOnTarget(SBBGCard minion, SBBGCard target);
       // return new RerollChoices();
       // return new FreezeChoices();
       // return new SellMinion(SBBGCard minion);

        return new DoNothing();
    }

    public Card.Cards HandleDiscoverChoices(List<Card.Cards> choices)
    {
        //3 choices when playing the "discover" card you get after upgrading a minion
        return choices[0];
    }

    public void OnNewGameSignalReceived()
    {
        //Reset your variables here
        Bot.Log("New game signal received");
    }

    public void OnNewTurnSignalReceived()
    {
        //Reset your variables here
        Bot.Log("New turn signal received");
    }
}

public static class BoardExtensions
{
    public static int GetLastIndex(this SBBGBoard board)
    {
        return board.Minions.Max(x => x.Index);
    }

    public static bool AreAllMinionsOnTheRightTaunts(this SBBGBoard board, SBBGCard minion)
    {
        foreach(var m in board.Minions.ToArray())
        {
            if (m.Index > minion.Index && !m.Taunt)
                return false;
        }
        return true;
    }

    public static bool CanBuyMinion(this SBBGBoard board)
    {
        return board.ManaAvailable >= 3 && board.Hand.Count <= 9;
    }

    public static bool CanPlayMinion(this SBBGBoard board)
    {
        return board.Hand.Count(x => !x.IsDiscover) > 0 && board.Minions.Count < 7;
    }

    public static bool HasDiscoverToPlay(this SBBGBoard board)
    {
        return board.Hand.Any(x => x.IsDiscover);
    }

    public static bool CanUpgradeTavern(this SBBGBoard board)
    {
        return board.ManaAvailable >= board.TavernLevelUpCost;
    }

    public static bool ContainsUpgradableCard(this SBBGBoard board)
    {
        var cardpool = board.Minions.Union(board.Hand);
        return cardpool.Any(x => !x.IsUpgraded && cardpool.Count(y => y.CardId == x.CardId) >= 2);
    }

    public static bool DoChoicesContainUpgradableCard(this SBBGBoard board)
    {
        var cardpool = board.Minions.Union(board.Hand);

        return (ContainsUpgradableCard(board) && board.Choices.Any(x => x.CardId == GetUpgradableCardIfAny(board).CardId));
    }

    public static SBBGCard GetUpgradableCardIfAny(this SBBGBoard board)
    {
        var cardpool = board.Minions.Union(board.Hand);
        return cardpool.FirstOrDefault(x => !x.IsUpgraded && cardpool.Count(y => y.CardId == x.CardId) >= 2);
    }
}